#include "Debug.hpp"
#include "LRUCache.hpp"

#include <fstream> 

namespace se {

LRUCache::LRUCache(size_t size): _size(size) { }

void LRUCache::print() {
    DEBUG_PRINT("\33[032;1m_resultList\33[0m has %lu records --->", _resultList.size());
    for(const auto & elem : _resultList) {
        // DEBUG_PRINT("%s %s", elem.first.c_str(), elem.second.dump().c_str());
        ::printf(" %s ", elem.first.c_str());
    }
    ::printf("\n");
#if 0
    DEBUG_PRINT("\33[032;1m_resultMap\33[0m has %lu records --->", _resultMap.size());
    for(const auto & elem : _resultMap) {
        DEBUG_PRINT("%s %s", (*elem.second).first.c_str(), (*elem.second).second.dump().c_str());
    }
    DEBUG_PRINT("\33[032;1m_pendingUpdateList\33[0m has %lu records --->", _pendingUpdateList.size());
    for(const auto & elem : _pendingUpdateList) {
        DEBUG_PRINT("%s %s", elem.first.c_str(), elem.second.dump().c_str());
    }
#endif
    DEBUG_PRINT("-----------------------------------------------");
}

void LRUCache::readFromFile(const std::string & fileName) {
    std::ifstream ifs(fileName);

    if(ifs.good()) {
        while(!ifs.eof() && _resultList.size() < _size) {
            _resultList.push_back(std::make_pair(Key(), json()));  //先插入元素，再从文件中直接写入该元素，减少一次拷贝          
            auto iter = --_resultList.end();  //指向新插入的元素的迭代器
            ifs >> iter->first;
            if(ifs.eof()) {
                _resultList.pop_back();
                break;
            }
            ifs >> iter->second;
            _resultMap.insert(std::make_pair(iter->first, iter));
        }
        ifs.close();

    }
    else {
        DEBUG_PRINT("open file \"%s\" for reading failed.", fileName.c_str());
    }
}

void LRUCache::writeToFile(const std::string & fileName) {
    std::ofstream ofs(fileName);
    if(ofs.good()) {
        for(const auto & elem : _resultList) {
            ofs << elem.first << " " << elem.second << std::endl;
        }
    }
    else {
        DEBUG_PRINT("open file \"%s\" for writing failed.", fileName.c_str());
    }
}

void LRUCache::movePendingUpdateListTo(LRUCache & cache) {
    if(&cache != this) {
        //直接把_pendingUpdateList连接到目标cache的_pendingUpdateList上
        cache._pendingUpdateList.splice(cache._pendingUpdateList.end(), _pendingUpdateList);
    }
}

void LRUCache::copyFrom(const LRUCache & cache) {
    if(&cache != this) {
        _resultList = cache._resultList;
        regenerateResultMap();
    }
}

void LRUCache::regenerateResultMap() {
    _resultMap.clear();
    auto iter = _resultList.begin();
    while(iter != _resultList.end()) {    
        _resultMap.insert(std::make_pair(iter->first, iter));
        ++iter;
    }
}

void LRUCache::addRecord(const std::pair<Key, json> & record) {
    //插入记录前要确保Cache中无此记录
    if(_resultList.size() == _size) {
        throwOutRecord();
    }
    _resultList.push_front(record);
    _resultMap.insert(std::make_pair(record.first, _resultList.begin()));
    _pendingUpdateList.push_front(record);
}

std::shared_ptr<nlohmann::json> LRUCache::find(const Key & key) {

    auto mapIterator = _resultMap.find(key);
    if(mapIterator != _resultMap.end()) {
        auto listIterator = mapIterator->second;
        reNewRecord(listIterator);
        return std::shared_ptr<nlohmann::json>(new nlohmann::json(listIterator->second));
    }
    DEBUG_PRINT("nodata");
    return std::shared_ptr<nlohmann::json>(new nlohmann::json()); 
}

void LRUCache::updateSelf() {
    while(!_pendingUpdateList.empty()) {
        auto listIterator = _pendingUpdateList.begin();
        auto mapIterator = _resultMap.find(listIterator->first); 
        if(mapIterator == _resultMap.end()) {
            //插入前先判断_resultList是否达到容量上限
            if(_resultList.size() == _size) {
                throwOutRecord();
            }
            _resultList.splice(_resultList.begin(), _pendingUpdateList, listIterator);
            _resultMap.insert(std::make_pair(listIterator->first, _resultList.begin()));
        }
        else {
            reNewRecord(mapIterator->second);
            _pendingUpdateList.pop_front();
        }
    }
}

void LRUCache::throwOutRecord() {
    auto deleteIterator = --_resultList.end();
    _resultMap.erase(deleteIterator->first);
    _resultList.pop_back();
}

void LRUCache::reNewRecord(Cache::iterator iter) {
    //先把该元素移到_pendingUpdateList，再移回_resultList头部，避免拷贝和_resultMap的重新插入
    _pendingUpdateList.splice(_pendingUpdateList.begin(), _resultList, iter);           
    _resultList.splice(_resultList.begin(), _pendingUpdateList, _pendingUpdateList.begin());
}

void LRUCache::clear() {
    _resultList.clear();
    _resultMap.clear();
    _pendingUpdateList.clear();
}

}  // end of namespace se
